package info.emamian.droplet.worker.sms;

import info.emamian.droplet.data.DynamoDbSms;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class SMSService {
	// private static final Logger logger =
	// LoggerFactory.getLogger(SMSService.class);
	private final Map<String, List<AbstractSMSHandler>> handlers = new HashMap<String, List<AbstractSMSHandler>>();
	private static final Logger logger = LoggerFactory
			.getLogger(SMSService.class);

	public boolean registerHandler(final String khandlerKey,
			final AbstractSMSHandler handler) {
		if (khandlerKey == null) {
			throw new IllegalArgumentException("hanlder key cannot be null");
		}
		String key = khandlerKey.trim();
		if (key.isEmpty()) {
			throw new IllegalArgumentException("hanlder key cannot be empty");
		}

		// create handler list for key if not exist
		if (!handlers.containsKey(key)) {
			handlers.put(key, new ArrayList<AbstractSMSHandler>());
		}

		List<AbstractSMSHandler> list = handlers.get(key);
		if (!list.contains(handler)) {// prevent duplicate
			list.add(handler);
		}
		return true;
	}

	public void unRegisterHandler(final String handlerKey,
			final AbstractSMSHandler handler) {
		if (handlerKey == null || handlerKey.trim().isEmpty()) {
			throw new IllegalArgumentException("handlerKey cannot be null");
		}
		String key = handlerKey.trim();
		if (handlers.containsKey(key)) {
			List<AbstractSMSHandler> list = handlers.get(key);
			boolean removed = list.remove(handler);
			if (!removed && logger.isDebugEnabled()) {
				logger.warn(String.format(
						"Trying to remove non-existing Handler [%s]",
						handlerKey));
			}
		}
	}

	/**
	 * Retrieves best answer from appropriate handler for <code>sms</code> based
	 * on first word of sms
	 * 
	 * @param sms
	 *            input sms that should be handled by appropriate
	 *            <code>AbstractSMSHandler</code>
	 * @return answer to <code>sms</code> or <code>allHandlersUsage</code> if
	 *         first word is a reserved word.
	 */
	public String getAnswerFromAppropriateHandler(final DynamoDbSms sms) {
		if (sms == null || sms.isEmpty()) {
			return null;
		}
		String firstWord = sms.getFirstWord();
		// check for reserved words e.g. help, cmd
		if (isReseverdWord(firstWord)) {
			return getAllHandlersUsage();
		}

		// check handlers for appropriate answer
		if (handlers.containsKey(firstWord)) {
			List<AbstractSMSHandler> listOfHandlers = handlers.get(firstWord);
			for (Iterator<AbstractSMSHandler> iterator = listOfHandlers
					.iterator(); iterator.hasNext();) {
				AbstractSMSHandler smsHandler = iterator.next();
				if (smsHandler.canAnswer(sms)) {
					String answer = smsHandler.getAnswer();
					if (answer != null && !answer.trim().isEmpty()) {
						return answer;
					}
				}
			}
		}
		// TODO handle other than first word cases

		// no answer found
		return null;
	}

	/**
	 * Check if the <code>word</code> is a reserved word.
	 * 
	 * @param word
	 * @return
	 */
	public boolean isReseverdWord(final String word) {
		if (word == null) {
			return false;
		}
		String w = word.trim();
		return (w.equalsIgnoreCase("help") || w.equalsIgnoreCase("?")
				|| w.equalsIgnoreCase("hlp") || w.equalsIgnoreCase("cmd"));
	}

	/**
	 * @return Concatenation of all handlers' usages
	 */
	public String getAllHandlersUsage() {
		String ret = "";
		Collection<List<AbstractSMSHandler>> allHandlers = handlers.values();
		for (Iterator<List<AbstractSMSHandler>> allHandlersIterator = allHandlers
				.iterator(); allHandlersIterator.hasNext();) {
			List<AbstractSMSHandler> handlersList = allHandlersIterator.next();

			for (Iterator<AbstractSMSHandler> handlerIterator = handlersList
					.iterator(); handlerIterator.hasNext();) {
				AbstractSMSHandler abstractSMSHandler = handlerIterator.next();
				if (!ret.isEmpty()) {
					ret += ",";
				}
				ret += abstractSMSHandler.getUsage();
			}
		}
		ret = ret.trim();
		if (ret.isEmpty()) {
			return null;
		}
		return ret;
	}

	/**
	 * @param handlerKey
	 * @return null or empty string if <code>handlerKey</code> has not handlers
	 */
	public String getAllHandlersUsageForKeyword(final String handlerKey) {
		if (handlerKey == null) {
			return null;
		}
		List<AbstractSMSHandler> handlersList = handlers.get(handlerKey);
		if (handlersList == null) {
			return null;
		}
		String ret = "";
		for (Iterator<AbstractSMSHandler> handlerIterator = handlersList
				.iterator(); handlerIterator.hasNext();) {
			AbstractSMSHandler abstractSMSHandler = handlerIterator.next();
			if (!ret.isEmpty()) {
				ret += ",";
			}
			ret += abstractSMSHandler.getUsage();
		}
		ret = ret.trim();
		return ret;
	}

	public SMSService() {
		// logger.error("===============================================================");
		// logger.info("SMSInitialization onApplicationEvent");
		// // try {
		// // // mongoTemplate.getDb();
		// // logger.info("Collection sms found : {}",
		// // mongoTemplate.getCollectionNames().contains("sms"));
		// // }
		// // catch (Exception e) {
		// // // TODO: handle exception
		// // logger.error("Mongo DB error during initialization", e);
		// // }
		// try {
		// logger.info("Registered sms handler for drug : {}",
		// this.registerHandler("drug", new
		// DrugInfoHandler(event.getApplicationContext().getParent())));
		//
		// }
		// catch (Exception e) {
		// logger.error("SMS service error during initialization", e);
		// }
		// logger.error("===============================================================");

	}
}
